﻿#ifndef SERIALIZEMACRO_HPP
#define SERIALIZEMACRO_HPP
/************************************************
  * 描述: 封装、实现数据的序列化
  * File: serializemacro.h
  * Author: qijiangyong@mozihealthcare.cn
  * Date: 2025-06-27
  * Update:
  ***********************************************/
//rapidjson header
//#define BOOST_PFR_USE_CPP20_FLAG 1
//#define BOOST_PFR_ENABLE_FIELDS_NAMES
#include <string>
#include <vector>
#include <map>
#include <optional>

#include <QString>
#include <QVector>
#include <QList>
#include <QMap>
#include <QHash>
#include <QDateTime>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/prettywriter.h>
#include <common/xlist.hpp>

#ifdef _MSC_VER
#pragma warning(disable: 4189) // 局部变量已定义但未引用
#endif

//namespace pfr = boost::pfr;
////////////////////////////////////////////////////////////
// RapidJSON适配器与宏
template<typename T>
struct rapidjson_struct_adapter;

// std::vector<T> 特化版本
template<typename T>
struct rapidjson_struct_adapter<std::vector<T>> {
    using VectorType = std::vector<T>;

    template<typename F>
    static void for_each_field(const VectorType& obj, F&& f) {
        for (const auto& item : obj) {
            // vector 没有字段名，传空字符串作为 name
            rapidjson_struct_adapter<T>::for_each_field(item, [&](const char* name, const auto& field) {
                f(name, field);
            });
        }
    }

    template<typename F>
    static void for_each_field(VectorType& obj, F&& f) {
        for (auto& item : obj) {
            rapidjson_struct_adapter<T>::for_each_field(item, [&](const char* name, auto& field) {
                f(name, field);
            });
        }
    }
};

// 非侵入式宏定义
#define RAPIDJSON_ADAPT_STRUCT(type, ...) \
    template<> \
    struct rapidjson_struct_adapter<type> { \
        using T = type; \
        template<typename F> \
        static void for_each_field(const T& obj, F&& f) { \
            adapt_fields(obj, std::forward<F>(f), ##__VA_ARGS__); \
        } \
        template<typename F> \
        static void for_each_field(T& obj, F&& f) { \
            adapt_fields(obj, std::forward<F>(f), ##__VA_ARGS__); \
        } \
    }; \
    inline void rapidjson_adapt_struct_dummy_func_##type() {}

// 辅助展开参数包（const版本 - 用于序列化）
template<typename T, typename F, typename First, typename... Rest>
void adapt_fields(const T& obj, F&& f, const char* name, const First T::*member, const Rest&... rest) {
    f(name, obj.*member);
    adapt_fields(obj, std::forward<F>(f), rest...);
}

// 辅助展开参数包（非const版本 - 用于反序列化）
template<typename T, typename F, typename First, typename... Rest>
void adapt_fields(T& obj, F&& f, const char* name, First T::*member, const Rest&... rest) {
    f(name, obj.*member); // 这里只会被非 const 字段调用
    adapt_fields(obj, std::forward<F>(f), rest...);
}

// 终止递归
inline void adapt_fields(...) {}
////////////////////////////////////////////////////////////
// 辅助模板
template<typename Test, template<typename...> class Ref>
struct is_specialization_of : std::false_type {};

template<template<typename...> class Ref, typename... Args>
struct is_specialization_of<Ref<Args...>, Ref> : std::true_type {};

template<typename Test, template<typename...> class Ref>
inline constexpr bool is_specialization_of_v = is_specialization_of<Test, Ref>::value;
// 判断是否是 POD 结构体类型（可被 PFR 反射）
//template<typename T>
//inline constexpr bool is_reflectable_struct_v =
//    pfr::tuple_size< std::decay_t<T> >::value > 0;

// ========================
// 元编程辅助工具
// ========================
template <typename T>
struct is_optional : std::false_type {};

template <typename T>
struct is_optional<std::optional<T>> : std::true_type {};

template <typename T>
inline constexpr bool is_optional_v = is_optional<T>::value;

// rapidjson泛型函数
// 序列化
template<typename T>
void to_json_value(const T& obj, rapidjson::Value& value, rapidjson::Document::AllocatorType& alloc) {
    using FieldType = std::decay_t<T>;

    // 处理 optional 类型
    if constexpr (is_optional_v<FieldType>) {
        if (obj.has_value()) {
            // 递归序列化包含的值
            to_json_value(*obj, value, alloc);
        }
        else {
            // 设置为 null
            value.SetNull();
        }
    } else if constexpr (std::is_same_v<FieldType, std::string>) {
        value.SetString(obj.c_str(), alloc);
    } else if constexpr (std::is_same_v<FieldType, const char*>) {
        value.SetString(obj, alloc);
    } else if constexpr (std::is_same_v<FieldType, bool>) {
        value.SetBool(obj);
    } else if constexpr (std::is_integral_v<FieldType> && !std::is_same_v<FieldType, bool>) {
        if constexpr (sizeof(FieldType) <= sizeof(int)) {
            value.SetInt(static_cast<int>(obj));
        } else {
            value.SetInt64(static_cast<int64_t>(obj));
        }
    } else if constexpr (std::is_floating_point_v<FieldType>) {
        value.SetDouble(static_cast<double>(obj));
    } else if constexpr (is_specialization_of_v<FieldType, std::vector>) {
        value.SetArray();
        value.Reserve(static_cast<rapidjson::SizeType>(obj.size()), alloc);
        for (const auto& item : obj) {
            rapidjson::Value elem;
            to_json_value(item, elem, alloc);
            value.PushBack(elem, alloc);
        }
    } else if constexpr (is_specialization_of_v<FieldType, std::map>) {
        value.SetObject();
        for (const auto& [k, v] : obj) {
            rapidjson::Value key(k.c_str(), alloc);
            rapidjson::Value val;
            to_json_value(v, val, alloc);
            value.AddMember(key.Move(), val, alloc);
        }
    } // 添加对 Qt 类型字段的支持
    // qint64
    else if constexpr (std::is_same_v<FieldType, qint64>) {
        value.SetInt64(obj);
    }
    // qint32
    else if constexpr (std::is_same_v<FieldType, qint32>) {
        value.SetInt(static_cast<int>(obj)); // qint32 -> int
    }
    // quint8
    else if constexpr (std::is_same_v<FieldType, quint8>) {
        // value.SetUint(static_cast<unsigned>(obj)); // quint8 -> unsigned
        char str[2] = { static_cast<char>(obj), '\0' };
        value.SetString(str, 1, alloc);
    }
    // qreal
    else if constexpr (std::is_same_v<FieldType, qreal>) {
        value.SetDouble(static_cast<double>(obj));
    }
    // QString
    else if constexpr (std::is_same_v<FieldType, QString>) {
        QByteArray utf8Data = obj.toUtf8();
        // qDebug() << "utf8data:" << QString::fromUtf8(utf8Data).toLocal8Bit().constData();
        value.SetString(utf8Data.constData(), utf8Data.size(), alloc);
    }
	// QVariant
	else if constexpr (std::is_same_v<FieldType, QVariant>)
	{
		auto type = obj.type();
		switch (type)
		{
		case QVariant::ByteArray:
		case QVariant::String: {
			QByteArray utf8Data = obj.toString().toUtf8();
			value.SetString(utf8Data.constData(), utf8Data.size(), alloc);
		}
			break;
		case QVariant::StringList: {
			auto strTemp = obj.toStringList().join(';').toUtf8();
			value.SetString(strTemp.constData(), strTemp.size(), alloc);
		}
			break;
		case QVariant::Int: {
			value.SetInt64(obj.toInt());
		}
			break;
		case QVariant::UInt: {
			value.SetUint64(obj.toUInt());
		}
			break;
		case QVariant::LongLong: {
			value.SetInt64(obj.toLongLong());
		}
			break;
		case QVariant::ULongLong: {
			value.SetUint64(obj.toULongLong());
		}
			break;
		case QVariant::Double: {
			value.SetDouble(obj.toDouble());
		}
			break;
		case QVariant::Char: {
			value.SetInt(static_cast<int>(obj.toInt()));
		}
			break;
		case QVariant::Bool: {
			value.SetBool(obj.toBool());
		}
			break;
		case QVariant::Date: {
			value.SetString(obj.toDate().toString("yyyy-MM-dd").toStdString().c_str(), alloc);
		}
			break;
		case QVariant::Time: {
			value.SetString(obj.toTime().toString("HH:mm:ss").toStdString().c_str(), alloc);
		}
			break;
		case QVariant::DateTime: {
			value.SetString(obj.toDateTime().toString("yyyy-MM-dd HH:mm:ss").toStdString().c_str(), alloc);
		}
			break;
		case QVariant::Map: {
			value.SetObject();
			auto mobj = obj.toMap();
			for (auto it = mobj.begin(); it != mobj.end(); ++it) {
				rapidjson::Value key(it.key().toUtf8().constData(), alloc);
				rapidjson::Value val;
				to_json_value(it.value(), val, alloc);
				value.AddMember(key.Move(), val, alloc);
			}
		}
			break;
		case QVariant::List: {
			value.SetArray();
			auto list = obj.toList();
			value.Reserve(static_cast<rapidjson::SizeType>(list.size()), alloc);
			for (const auto& item : list) {
				rapidjson::Value elem;
				to_json_value(item, elem, alloc);
				value.PushBack(elem, alloc);
			}
		}
			break;
		default:
			value.SetNull();
			break;
		}
	}
    // QDateTime
    else if constexpr (std::is_same_v<FieldType, QDateTime>) {
        value.SetString(obj.toString("yyyy-MM-dd HH:mm:ss").toStdString().c_str(), alloc);
    }
    // QDate
    else if constexpr (std::is_same_v<FieldType, QDate>) {
        value.SetString(obj.toString("yyyy-MM-dd").toStdString().c_str(), alloc);
    }
    // QTime
    else if constexpr (std::is_same_v<FieldType, QTime>) {
        value.SetString(obj.toString("HH:mm:ss").toStdString().c_str(), alloc);
    }
    // QList
    else if constexpr (is_specialization_of_v<FieldType, QList>) {
        value.SetArray();
        value.Reserve(static_cast<rapidjson::SizeType>(obj.size()), alloc);
        for (const auto& item : obj) {
            rapidjson::Value elem;
            to_json_value(item, elem, alloc);
            value.PushBack(elem, alloc);
        }
    }
	// XList
	else if constexpr (is_specialization_of_v<FieldType, xlist::XList>) {
		value.SetArray();
		value.Reserve(static_cast<rapidjson::SizeType>(obj.ToList().size()), alloc);
		for (const auto& item : obj.ToList()) {
			rapidjson::Value elem;
			to_json_value(item, elem, alloc);
			value.PushBack(elem, alloc);
		}
	}
    // QVector
    else if constexpr (is_specialization_of_v<FieldType, QVector>) {
        value.SetArray();
        value.Reserve(static_cast<rapidjson::SizeType>(obj.size()), alloc);
        for (const auto& item : obj) {
            rapidjson::Value elem;
            to_json_value(item, elem, alloc);
            value.PushBack(elem, alloc);
        }
    }
    // QMap
    else if constexpr (is_specialization_of_v<FieldType, QMap>) {
        value.SetObject();
        for (auto it = obj.begin(); it != obj.end(); ++it) {
            rapidjson::Value key(it.key().toUtf8().constData(), alloc);
            rapidjson::Value val;
            to_json_value(it.value(), val, alloc);
            value.AddMember(key.Move(), val, alloc);
        }
    }
    // QHash
    else if constexpr (is_specialization_of_v<FieldType, QHash>) {
        value.SetObject();
        for (auto it = obj.begin(); it != obj.end(); ++it) {
            rapidjson::Value key(it.key().toUtf8().constData(), alloc);
            rapidjson::Value val;
            to_json_value(it.value(), val, alloc);
            value.AddMember(key.Move(), val, alloc);
        }
    }    
    else { // static_assert(sizeof(FieldType) == 0, "Unsupported type in to_json_value");
        value.SetObject();
        rapidjson_struct_adapter<FieldType>::for_each_field(obj, [&](const char* name, const auto& field) {
            rapidjson::Value key(name, alloc);
            rapidjson::Value val;
            to_json_value(field, val, alloc);
            value.AddMember(key.Move(), val, alloc);
        });
    }
}
// 反序列化
template<typename T>
void from_json_value(const rapidjson::Value& value, T& obj) {
    using TDecay = std::decay_t<T>;

    // std::cout << "[DEBUG] T = " << typeid(T).name() << ", TDecay = " << typeid(TDecay).name() << std::endl;

    if constexpr (is_specialization_of_v<TDecay, std::vector>) {
        // std::cout << "[INFO] Handling vector" << std::endl;
        if (value.IsArray()) {
            obj.clear();
            for (const auto& elem : value.GetArray()) {
                typename TDecay::value_type t{};
                from_json_value(elem, t);
                obj.push_back(std::move(t));
            }
        }        
    } else if constexpr (is_specialization_of_v<TDecay, std::map>) {
        // std::cout << "[INFO] Handling map" << std::endl;
        if (value.IsObject()) {
            obj.clear();
            for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
                typename TDecay::key_type key = it->name.GetString();
                typename TDecay::mapped_type val{};
                from_json_value(it->value, val);
                obj[std::move(key)] = std::move(val);
            }
        }
    } else if constexpr (is_optional_v<TDecay>) {    // 处理 optional 类型
            if (value.IsNull()) {
                obj = std::nullopt;
            }
            else {
                // 创建值并递归解析
                typename TDecay::value_type temp;
                from_json_value(value, temp);
                obj = std::move(temp);
            }
    } else if constexpr (std::is_same_v<TDecay, std::string>) {
        // std::cout << "[INFO] Handling string" << std::endl;
        static_assert(std::is_assignable_v<std::remove_const_t<std::remove_reference_t<T>>, decltype(value.GetString())>,
                      "T must be assignable from rapidjson string");

        if (value.IsString()) {
            obj = value.GetString();
        }
    } else if constexpr (std::is_integral_v<TDecay> && !std::is_same_v<TDecay, bool>) {
        // std::cout << "[INFO] Handling integral" << std::endl;
        if (value.IsInt()) {
            obj = static_cast<TDecay>(value.GetInt());
        }
    } else if constexpr (std::is_floating_point_v<TDecay>) {
        // std::cout << "[INFO] Handling floating point" << std::endl;
        if (value.IsDouble()) {
            obj = static_cast<TDecay>(value.GetDouble());
        }
    } else if constexpr (std::is_same_v<TDecay, bool>) {
        // std::cout << "[INFO] Handling bool" << std::endl;
        if (value.IsBool()) {
            obj = value.GetBool();
        }
    } // 添加对 Qt 类型字段的支持
    // qint64
    else if constexpr (std::is_same_v<TDecay, qint64>) {
        if (value.IsInt64()) {
            obj = static_cast<qint64>(value.GetInt64());
        }
    }
    // qint32
    else if constexpr (std::is_same_v<TDecay, qint32>) {
        if (value.IsInt()) {
            obj = static_cast<qint32>(value.GetInt());
        }
    }
    // quint8
    else if constexpr (std::is_same_v<TDecay, quint8>) {
//        if (value.IsUint()) {
//            obj = static_cast<quint8>(value.GetUint());
//        }
        if (value.IsString()) {
            const char* str = value.GetString();
            size_t len = strlen(str);

            if (len >= 1)
                obj = static_cast<quint8>(str[0]);
        } // 如果不是字符串或为空，则尝试是否是数字（兼容历史数据）
        else if (value.IsInt()) {
            int val = value.GetInt();
            if (val >= 0 && val <= 255)
                obj = static_cast<quint8>(val);
        }
    }
    // qreal
    else if constexpr (std::is_same_v<TDecay, qreal>) {
        if (value.IsNumber()) {
            obj = static_cast<qreal>(value.GetDouble());
        }
    }
    // QString
    else if constexpr (std::is_same_v<TDecay, QString>) {
        if (value.IsString()) {
            obj = QString::fromUtf8(value.GetString());
        }
    }
	// QVariant
	else if constexpr (std::is_same_v<TDecay, QVariant>)
	{
		if (value.IsString())
		{
			obj = QVariant::fromValue(QString::fromUtf8(value.GetString()));
			// obj = QVariant::fromValue(value);
		}
		else if (value.IsNumber())
		{
			if (value.IsInt() || value.IsInt64())
				obj = QVariant::fromValue(value.GetInt64());
			else
				obj = QVariant::fromValue(value.GetDouble());
		}
		else if (value.IsBool())
		{
			obj = QVariant::fromValue(value.GetBool());
		}
		else if (value.IsNull())
		{
			obj = QVariant();
		}
		else if (value.IsArray())
		{
			obj = QVariant::fromValue(value.GetArray());
		}
		else if (value.IsObject())
		{
			obj = QVariant::fromValue(value.GetObject());
		}
		else
		{
			obj = QVariant::fromValue(value);
		}
	}
    // QDateTime
    else if constexpr (std::is_same_v<TDecay, QDateTime>) {
        if (value.IsString()) {
            obj = QDateTime::fromString(QString::fromUtf8(value.GetString()), "yyyy-MM-dd HH:mm:ss");
        }
    }
    // QDate
    else if constexpr (std::is_same_v<TDecay, QDate>) {
        if (value.IsString()) {
            obj = QDate::fromString(QString::fromUtf8(value.GetString()), "yyyy-MM-dd");
        }
    }
    // QTime
    else if constexpr (std::is_same_v<TDecay, QTime>) {
        if (value.IsString()) {
            obj = QTime::fromString(QString::fromUtf8(value.GetString()), "HH:mm:ss");
        }
    }
    // QList
    else if constexpr (is_specialization_of_v<TDecay, QList>) {
        if (value.IsArray()) {
            obj.clear();
            for (const auto& elem : value.GetArray()) {
                typename TDecay::value_type t{};
                from_json_value(elem, t);
                obj.append(std::move(t));
            }
        }
    }
	// XList
	else if constexpr (is_specialization_of_v<TDecay, xlist::XList>) {
		if (value.IsArray()) {
			obj.clear();
			for (const auto& elem : value.GetArray()) {
				typename TDecay::value_type t{};
				from_json_value(elem, t);
				obj.Add(std::move(t));
			}
		}
	}
    // QVector
    else if constexpr (is_specialization_of_v<TDecay, QVector>) {
        if (value.IsArray()) {
            obj.clear();
            for (const auto& elem : value.GetArray()) {
                typename TDecay::value_type t{};
                from_json_value(elem, t);
                obj.push_back(std::move(t));
            }
        }
    }
    // QMap
    else if constexpr (is_specialization_of_v<TDecay, QMap>) {
        if (value.IsObject()) {
            obj.clear();
            for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
                QString key = QString::fromUtf8(it->name.GetString());
                typename TDecay::mapped_type val{};
                from_json_value(it->value, val);
                obj.insert(std::move(key), std::move(val));
            }
        }
    }
    // QHash
    else if constexpr (is_specialization_of_v<TDecay, QHash>) {
        if (value.IsObject()) {
            obj.clear();
            for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
                QString key = QString::fromUtf8(it->name.GetString());
                typename TDecay::mapped_type val{};
                from_json_value(it->value, val);
                obj.insert(std::move(key), std::move(val));
            }
        }
    } else {
        static_assert(!std::is_const_v<T>, "from_json_value requires a non-const object");
        //static_assert(sizeof(T) == 0, "Unsupported type in from_json_value");

        rapidjson_struct_adapter<TDecay>::for_each_field(obj, [&](const char* name, auto& field) {            
            auto it = value.FindMember(name);
            if (it != value.MemberEnd()) {                
                // 最终防线：只对非 const 字段进行反序列化
                //std::cout << "[DEBUG] Field: " << name
                //    << ", type of field: " << typeid(decltype(field)).name()
                //    << std::endl;
                if constexpr (!std::is_const_v<std::remove_reference_t<decltype(field)>>) {                    
                    from_json_value(it->value, field);
                }
            }
        });
    }
}

#endif // SERIALIZEMACRO_HPP
